<?php
class User_model_user extends Model {
    private $table = 'user';
    private $table_group = 'group';
    private $table_role = 'role';
    private $table_position = 'position';
    private $table_position_relation = 'user_position';
    
    private $admin_position_id = 0;
    
    
    public function add($username, $password, $email, $group = '', $role = '') {
        $username = trim($username);
        $password = trim($password);
        $email = trim($email);
        $group = trim($group);
        $role = trim($role);
        
        if (empty($username) || empty($password)) {
            return false;
        }
        
        if ($this->exists($username)) {
            return false;
        }
        
        $created = time();
        $changed = $created;
        
        $this->db->trans_start();
        $user_id = $this->db->insert($this->table, array(
            'username'  => $username,
            'passcode'  => $this->_generate_passcode($password, $created),
            'email'     => $email,
            'created'   => $created,
            'changed'   => $changed
        ));
        
        if ( ! $user_id) {
            $this->db->trans_rollback();
            return false;
        }
        
        if ( ! empty($group)) {
            if ( ! $this->add_position($user_id, $group, $role)) {
                $this->db->trans_rollback();
                return false;
            }
        }
        $this->db->trans_commit();
        return $user_id;
    }
    
    public function add_position($user_id, $groupname, $rolename='') {
        $group = trim($groupname);
        $role = trim($rolename);
        $this->db->trans_start();
        $group_id = (int) $this->add_group($group);
        $role_id = 0;
        $position_id = 0;
        
        if ($group_id <= 0) {
            $this->db->trans_rollback();
            return false;
        }
        
        if ( ! empty($role)) {
            $role_id = (int) $this->add_role($role);
        }
        
        
        $position_id = $this->_add_position($group_id, $role_id);
        if ($position_id <= 0) {
            $this->db->trans_rollback();
            return false;
        }
        
        $relaction_id = (int) $this->_add_position_relaction($user_id, $position_id);
        
        if ($relaction_id <= 0) {
            $this->db->trans_rollback();
            return false;
        }
        $this->db->trans_commit();
        return true;
    }
    
    public function add_group($groupname, $description = '') {
        if ($group_id = $this->group_exists($groupname)) {
            return $group_id;
        }
        
        $new_group_id = $this->db->insert($this->table_group, array(
            'groupname'     => $groupname,
            'description'   => $description
        ));
        return $new_group_id;
    }
    
    public function group_exists($groupname) {
        $groupname = $this->db->escape_str($groupname);
        $sql = "SELECT `id` FROM `{$this->table_group}` WHERE `groupname`='{$groupname}' LIMIT 1";
        if ($row = $this->db->row($sql)) {
            return $row['id'];
        } else {
            return false;
        }
    }
    
    public function add_role($rolename, $description = '') {
        if ($role_id = $this->role_exists($rolename)) {
            return $role_id;
        }
        $new_role_id = $this->db->insert($this->table_role, array(
            'rolename'      => $rolename,
            'description'   => $description
        ));
        return $new_role_id;
    }
    
    public function role_exists($rolename) {
        $rolename = $this->db->escape_str($rolename);
        $sql = "SELECT `id` FROM `{$this->table_role}` WHERE `rolename`='{$rolename}' LIMIT 1";
        if ($row = $this->db->row($sql)) {
            return $row['id'];
        } else {
            return false;
        }
    }
    
    public function _add_position($group_id, $role_id) {
        $group_id = (int) $group_id;
        $role_id = (int) $role_id;
        if ($position_id = $this->position_exists($group_id, $role_id)) {
            return $position_id;
        }
        
        $new_position_id = $this->db->insert($this->table_position, array(
            'group_id'      => $group_id,
            'role_id'       => $role_id
        ));
        return $new_position_id;
    }
    
    public function position_exists($group_id, $role_id) {
        $group_id = (int) $group_id;
        $role_id = (int) $role_id;
        
        $sql = "SELECT `id` FROM `{$this->table_position}` WHERE `group_id`='{$group_id}' AND `role_id`='{$role_id}' LIMIT 1";
        if ($row = $this->db->row($sql)) {
            return $row['id'];
        } else {
            return false;
        }
    }
    
    public function _add_position_relaction($user_id, $position_id) {
        $user_id = (int) $user_id;
        $position_id = (int) $position_id;
        
        if ($position_relation_id = $this->position_relation_exists($user_id, $position_id)) {
            return $position_relation_id;
        }
        
        $new_position_relation_id = $this->db->insert($this->table_position_relation, array(
            'user_id'       => $user_id,
            'position_id'    => $position_id
        ));
        
        return $new_position_relation_id;
    }
    
    public function position_relation_exists($user_id, $position_id) {
        $user_id = (int) $user_id;
        $position_id = (int) $position_id;
        
        $sql = "SELECT `id` FROM `{$this->table_position_relation}` WHERE `user_id`='{$user_id}' AND `position_id`='{$position_id}' LIMIT 1";
        if ($row = $this->db->row($sql)) {
            return $row['id'];
        } else {
            return false;
        }
    }
    
    public function exists($username) {
        $usernaem = $this->db->escape_str($username);
        $sql = "SELECT `id` FROM `{$this->table}` WHERE `username`='{$username}' LIMIT 1";
        if ($row = $this->db->row($sql)) {
            return $row['id'];
        } else {
            return false;
        }
    }
    
    public function authenticate($username, $password) {
        $username = trim($username);
        $password = trim($password);
        $username = $this->db->escape_str($username);
        $password = $this->db->escape_str($password);
        $sql = "SELECT `id`, `passcode`, `created` FROM `{$this->table}` WHERE `username`='{$username}' LIMIT 1";
        if ($row = $this->db->row($sql)) {
            $passcode = $row['passcode'];
            $created = $row['created'];
            if ($passcode === $this->_generate_passcode($password, $created)) {
                return $row['id'];
            }
        }
        return false;
    }
    
    
    public function position_ids($user_id) {
        $user_id = (int) $user_id;
        
        $sql = "SELECT `position_id` FROM `{$this->table_position_relation}` WHERE `user_id`='{$user_id}'";
        
        $position_ids = array();
        if ($rows = $this->db->rows($sql)) {
            foreach ($rows as $row) {
                $position_ids[] = $row['position_id'];
            }
        }
        if ($position_ids) {
            return $position_ids;
        } else {
            return false;
        }
        
    }
    
    public function admin_position_id() {
        if ( ! $this->admin_position_id) {
            $sql = "SELECT `p`.`id` `id` FROM `{$this->table_position}` `p` " . 
                    "INNER JOIN `{$this->table_group}` `g` ON `p`.`group_id`=`g`.`id` " .
                    "INNER JOIN `{$this->table_role}` `r` ON `p`.`role_id`=`r`.`id` " .
                    "WHERE `g`.`groupname`='admin' AND `r`.`rolename`='admin' LIMIT 1";
            if ($row = $this->db->row($sql)) {
                $this->admin_position_id = $row['id'];
            } 
        }
        return $this->admin_position_id;
    }
    
    
    private function _generate_passcode($password, $created) {
        return '#$' . hash('sha256', $password. $this->_generate_salt($created));
    }
    private function _generate_salt($created) {
        $created = (string) $created;
        return substr(md5($created), 0, 16);
    }
}
?>